package com.pdf.controller;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pdf.bo.HeightIndex;
import com.pdf.bo.Invoice;
import com.pdf.bo.Project;
import io.micrometer.common.util.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.util.Matrix;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

class PdfInvoice {
    /**
     * user space units per inch
     */
    private static final float POINTS_PER_INCH = 72;

    /**
     * user space units per millimeter
     */
    private static final float POINTS_PER_MM = 1 / (10 * 2.54f) * POINTS_PER_INCH;

    private static Invoice getInvoice() {
        Invoice invoice = new Invoice();
        invoice.setFphm("22312000000000000000");
        invoice.setKprq("2022年12月15日");
        invoice.setGmfmc("xxxxxxx分公司");
        invoice.setGmfnsrsbh("91370100706000000N");
        invoice.setXsfmc("xxxxxxxx有限公司");
        invoice.setXsfnsrsbh("91370100706000000N");
        invoice.setBz("2301599813");
        invoice.setKpr("XXX");
        invoice.setJsSum("23392");
        invoice.setJsSumStr("拾肆万零柒佰捌拾壹圆整");


        List<Project> projectList = new ArrayList<>();
        float jeSum = 0;
        float seSum = 0;
        for (int i = 0; i < 10; i++) {
            Project project2 = new Project();
            project2.setHwhyslwfwmc("*XXXXX*蝶阀");
//            project2.setGgxh("Tri-offset CL1 50RF CF3M STLD N150 " + i);
            project2.setGgxh("Tri-offset CL1 5F STLD N150 " + i);
            project2.setDw("台");
            project2.setSl("1");
            project2.setDj("4620.35398238");
            project2.setJe("4620.35");
            project2.setSlv("13%");
            project2.setSe("600.65");
            projectList.add(project2);

            jeSum += Float.parseFloat(project2.getJe());
            seSum += Float.parseFloat(project2.getSe());
        }

        invoice.setJeSum(String.valueOf(jeSum));
        invoice.setSeSum(String.valueOf(seSum));

        invoice.setProjectList(projectList);
        invoice.setBz("购方开户银行：xxx 银行账号：xxx  销方开户银行：xxx 银行账号：xxx 收款人：xxx 复核人：xxx");

        return invoice;
    }

    private static JsonNode getJson() {
        String directoryPath = "src/main/resources/data"; // 替换为你的目录路径
        String fileName = "project.json"; // JSON文件名

        try {
            // 构建文件路径
            String jsonFilePath = directoryPath + File.separator + fileName;
            // 读取文件内容到字符串
            String jsonString = new String(Files.readAllBytes(Paths.get(jsonFilePath)));
            // 创建ObjectMapper对象
            ObjectMapper objectMapper = new ObjectMapper();
            // 解析JSON字符串到JsonNode
            JsonNode jsonNode = objectMapper.readTree(jsonString);
            // 现在你可以使用jsonNode来访问JSON文件中的数据
            return jsonNode;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Float getPageHeight(int line, boolean isLast) {

        float addHeight = 140f;

        if (line <= 8) {
            return addHeight * POINTS_PER_MM;
        }

        System.out.println(PDRectangle.A4.getHeight());
        System.out.println(PDRectangle.A4.getHeight() / POINTS_PER_MM);

        if (line > 8 && line <= 42) {
            int tmp = line - 8;
            double ceil = 0;
            if (tmp > 4) {
                ceil = Math.ceil(tmp / 4f);
            } else {
                ceil = Math.ceil(4f / tmp);

            }
            return (float) ((17.5f * ceil + addHeight) * POINTS_PER_MM);
        }
        return PDRectangle.A4.getHeight();



/*
        int page = 1;
        if (line > 47) {
            double ceil = Math.ceil((double) line / 47);
            page = (int) ceil;
        }
        for (int i = 1; i <= page; i++) {
            if (i <= page - 1) {
                return ((addHeight + (47 - 8)*4.375f) * POINTS_PER_MM);
            } else {
                int tmpLine = line - (i - 1) * 47;
                if (tmpLine <= 8) {
                    return addHeight * POINTS_PER_MM;
                }
//                if (tmpLine > 8 && tmpLine <= 42) {
//                    return ((tmpLine - 8) * 4.375f + addHeight) * POINTS_PER_MM;
//                }
                if (tmpLine > 8 && tmpLine <= 47) {

                    return ((tmpLine-8) * 4.375f + addHeight) * POINTS_PER_MM;
                }
            }
        }*/
//        return 0f;
    }


    private static List<HeightIndex> wrapInvoiceToList(List<Project> list, PDType0Font font, float fontSize) throws IOException {

        JsonNode json = getJson();

        int countLine = 0;

        List<HeightIndex> indexList = new ArrayList<>();

        int ti = 0;
        for (int i = 0; i < list.size(); i++) {

            Project project = list.get(i);

            Class<? extends Project> projectClass = project.getClass();

            int line = 1;

            for (int i1 = 0; i1 < json.size(); i1++) {

                String key = json.get(i1).get("key").asText();
                float width = Float.parseFloat(json.get(i1).get("width").toString());

                width *= POINTS_PER_MM;
                try {
                    Field field1 = projectClass.getDeclaredField(key);
                    field1.setAccessible(true);
                    Object o = field1.get(project);
                    float wordWidth = font.getStringWidth(String.valueOf(o)) / 1000 * fontSize;

                    double ceil = 0;
                    if (wordWidth > width) {
                        ceil = Math.ceil(wordWidth / width);
                    } else {
                        continue;
//                        ceil = Math.ceil(wordWidth / width);
                    }

                    if (ceil > line) {
                        line = (int) ceil;
                    }

                } catch (NoSuchFieldException | IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
            countLine += line;

            if (countLine > 47) {
                float pageHeight = getPageHeight(countLine - line, false);

                i--;
                HeightIndex heightIndex = new HeightIndex();
                heightIndex.setIndex(i);
                heightIndex.setHeight(pageHeight);
                indexList.add(heightIndex);
                countLine = 0;
                ti = i;
            } else if (countLine == 47) {
                float pageHeight = getPageHeight(countLine, false);

                HeightIndex heightIndex = new HeightIndex();
                heightIndex.setIndex(i);
                heightIndex.setHeight(pageHeight);
                indexList.add(heightIndex);
                countLine = 0;
                ti = i;
            }

        }
        Float pageHeight = getPageHeight(countLine, true);
        HeightIndex heightIndex = new HeightIndex();
        heightIndex.setIndex(list.size() - 1);
        heightIndex.setHeight(pageHeight);
        indexList.add(heightIndex);

        return indexList;
    }

    private static List<String> wrapTextToLines(String text, float width, PDType0Font font, float fontSize) throws IOException {
        List<String> lines = new ArrayList<>();
        String[] words = text.split("");
        StringBuilder currentLine = new StringBuilder();
        float currentWidth = 0;

        for (String word : words) {
            float wordWidth = font.getStringWidth(word) / 1000 * fontSize;

            if (currentWidth + wordWidth > width) {
                if (StringUtils.isNotBlank(currentLine.toString())) {
                    lines.add(currentLine.toString().trim());
                }
                currentLine = new StringBuilder(word);
                currentWidth = wordWidth;
            } else {
                currentLine.append(word);
                currentWidth += wordWidth;
            }
        }

        if (currentLine.length() > 0) {
            lines.add(currentLine.toString().trim());
        }

        return lines;
    }

    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();

        try (PDDocument document = new PDDocument()) {
            JsonNode standard = mapper.readTree(new File("src/main/resources/data/project.json"));

            // 创建一个新页面
//            PDPage page = new PDPage(PDRectangle.A4);
            InputStream fontStream = new FileInputStream("src/main/resources/font/宋体.ttf");
//            InputStream fontStream = new FileInputStream("src/main/resources/font/FangSong_GB2312.ttf");
            InputStream kaiTi = new FileInputStream("src/main/resources/font/楷体.ttf");
            InputStream courier = new FileInputStream("src/main/resources/font/Courier New.ttf");
            InputStream courier_new = new FileInputStream("src/main/resources/font/Courier_New_main.ttf");

            PDType0Font stFont = PDType0Font.load(document, fontStream);
            PDType0Font courierFont = PDType0Font.load(document, courier);
            PDType0Font courierNewFont = PDType0Font.load(document, courier_new);

            fontStream.close();
            courier.close();
            courier_new.close();
            float fontSize9 = 9f;
            float fontSize11 = 11f;
            float fontSize12 = 12f;


            Invoice invoice = getInvoice();


            List<HeightIndex> indexList = wrapInvoiceToList(invoice.getProjectList(), stFont, fontSize9);

            System.out.println(indexList);

            PDType0Font ktFont = PDType0Font.load(document, kaiTi);
            kaiTi.close();


            PDImageXObject image = PDImageXObject.createFromFile("src/main/resources/images/qrCode.jpg", document);

            PDImageXObject signature = PDImageXObject.createFromFile("src/main/resources/images/测试章.jpg", document);

            PDImageXObject dx = PDImageXObject.createFromFile("src/main/resources/images/daxie.jpg", document);

            // 设置红褐色，这里使用RGB值
            float[] maroonRGB = new float[]{0.59f, 0.0f, 0.0f}; // 红褐色的近似RGB值
            PDColor maroonColor = new PDColor(maroonRGB, PDDeviceRGB.INSTANCE);

            // 黑色
            PDColor blackColor = PDDeviceRGB.INSTANCE.getInitialColor();
            float fontSize = 20f;


            float ktHeight = (ktFont.getFontDescriptor().getAscent() - ktFont.getFontDescriptor().getDescent()) / 1000 * fontSize9;

            float stHeight = (stFont.getFontDescriptor().getAscent() - stFont.getFontDescriptor().getDescent()) / 1000 * fontSize9;

            float dkHeight = (courierFont.getFontDescriptor().getAscent() - courierFont.getFontDescriptor().getDescent()) / 1000 * fontSize11;


            String mc = "名称：";
            String sh = "统一社会信用代码/纳税人识别号：";

            // 循环页数
            for (int ii = 0; ii < indexList.size(); ii++) {
                HeightIndex heightIndex = indexList.get(ii);

                PDRectangle customSize = new PDRectangle(210 * POINTS_PER_MM, heightIndex.getHeight());
                PDPage page = new PDPage(customSize);

                document.addPage(page);

                // 开始写入内容
                try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {

                    // 设置线条颜色为红褐色
                    contentStream.setStrokingColor(maroonColor);

                    contentStream.setNonStrokingColor(maroonColor);

                    // 页面宽度和高度
                    float pageWidth = page.getMediaBox().getWidth();
                    float pageHeight = page.getMediaBox().getHeight();

                    // 二维码
                    contentStream.drawImage(image, 7 * POINTS_PER_MM, customSize.getHeight() - 6 * POINTS_PER_MM - 20 * POINTS_PER_MM, 20 * POINTS_PER_MM, 20 * POINTS_PER_MM);

                    // 签章
                    contentStream.drawImage(signature, (pageWidth - 30 * POINTS_PER_MM) / 2, pageHeight - 28 * POINTS_PER_MM, 30 * POINTS_PER_MM, 20 * POINTS_PER_MM);

                    // 绘制票面
                    drawTable(contentStream, ktFont, page, indexList.size(), ii);

                    // 绘制线条
                    drawLine(contentStream, page, indexList.size(), ii);


                    contentStream.setFont(stFont, fontSize9);
                    contentStream.setStrokingColor(blackColor);
                    contentStream.setNonStrokingColor(blackColor);
                    // 购销方内容
                    showText(contentStream, 8.5f * POINTS_PER_MM + ktFont.getStringWidth(mc) / 1000 * fontSize9,
                            pageHeight - 36.5f * POINTS_PER_MM - ktHeight, invoice.getGmfmc());

                    // 销售方名称
                    showText(contentStream, 109f * POINTS_PER_MM + ktFont.getStringWidth(mc) / 1000 * fontSize9,
                            pageHeight - 36.5f * POINTS_PER_MM - ktHeight, invoice.getXsfmc());

                    // 发票号码
                    showText(contentStream, pageWidth - 35f * POINTS_PER_MM, pageHeight - 8 * POINTS_PER_MM - ktHeight, invoice.getFphm());

                    // 开票日期
                    showText(contentStream, pageWidth - 35 * POINTS_PER_MM, pageHeight - 8 * POINTS_PER_MM - ktHeight * 2 - 3 * POINTS_PER_MM, invoice.getKprq());


                    // 购买方税号
                    contentStream.setFont(courierNewFont, fontSize12);
                    showText(contentStream, 58 * POINTS_PER_MM,
                            pageHeight - 45.5f * POINTS_PER_MM, invoice.getGmfnsrsbh());
                    // 销售方税号
                    showText(contentStream, 109f * POINTS_PER_MM + ktFont.getStringWidth(sh) / 1000 * fontSize9,
                            pageHeight - 45.5f * POINTS_PER_MM, invoice.getXsfnsrsbh());

                    contentStream.setFont(stFont, fontSize9);

                    if (indexList.size() > 1) {
                        contentStream.beginText();
                        contentStream.setStrokingColor(blackColor);
                        contentStream.setNonStrokingColor(blackColor);
                        String ym = "共" + indexList.size() + "页 第" + (ii + 1) + "页";
                        contentStream.newLineAtOffset(pageWidth - (stFont.getStringWidth(ym) / 1000 * fontSize9) - 4.5f * POINTS_PER_MM, pageHeight - 29 * POINTS_PER_MM);
                        contentStream.showText(ym);
                        contentStream.endText();
                    }

                    int totalLine = 1;
                    int pi = ii > 0 ? indexList.get(ii - 1).getIndex() + 1 : 0;

                    // 项目明细内容
                    // 金额小计 税额小计
                    float jeSum = 0;
                    float seSum = 0;


                    for (; pi <= heightIndex.getIndex(); pi++) {
                        Project project = invoice.getProjectList().get(pi);

                        float ty = pageHeight - totalLine * 4.375f * POINTS_PER_MM - 56.5f * POINTS_PER_MM;
                        int line = 0;

                        Class<? extends Project> projectClass = project.getClass();

                        float totalWidth = 0f;
                        for (int i = 0; i < standard.size(); i++) {

                            JsonNode jsonNode = standard.get(i);
                            String text = jsonNode.get("key").asText();
                            float width = Float.parseFloat(jsonNode.get("width").asText());
                            String position = jsonNode.get("position").asText();

                            Field field = projectClass.getDeclaredField(text);

                            field.setAccessible(true);
                            List<String> strings = wrapTextToLines(field.get(project).toString(), width * POINTS_PER_MM, stFont, fontSize9);
                            line = Math.max(strings.size(), line);
                            for (int i1 = 0; i1 < strings.size(); i1++) {
                                contentStream.beginText();
                                if ("center".equals(position)) {
                                    float v = (width * POINTS_PER_MM - stFont.getStringWidth(field.get(project).toString()) / 1000 * fontSize9) / 2;
                                    contentStream.newLineAtOffset((4.5f + totalWidth) * POINTS_PER_MM + v, ty - i1 * 4.375f * POINTS_PER_MM);
                                } else if ("right".equals(position)) {
                                    float v = width * POINTS_PER_MM - stFont.getStringWidth(field.get(project).toString()) / 1000 * fontSize9;
                                    contentStream.newLineAtOffset((4.5f + totalWidth) * POINTS_PER_MM + v, ty - i1 * 4.375f * POINTS_PER_MM);
                                } else {
                                    contentStream.newLineAtOffset((4.5f + totalWidth) * POINTS_PER_MM, ty - i1 * 4.375f * POINTS_PER_MM);
                                }
                                contentStream.showText(strings.get(i1));
                                contentStream.endText();
                            }
                            totalWidth += width;

                        }
                        // 金额累加
                        jeSum += Float.parseFloat(project.getJe());
                        seSum += Float.parseFloat(project.getSe());

                        totalLine += line;

                    }
                    pi = heightIndex.getIndex();


                    if (indexList.size() > 1 && ii != indexList.size() - 1) {
                        // 小计
                        showText(contentStream, pageWidth - (25 + 27 + 4.5f) * POINTS_PER_MM - (stFont.getStringWidth(String.valueOf(jeSum)) / 1000 * fontSize9),
                                16 * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM + ktHeight), String.valueOf(jeSum));

                        showText(contentStream, pageWidth - 4.5f * POINTS_PER_MM - (stFont.getStringWidth(String.valueOf(seSum)) / 1000 * fontSize9),
                                16 * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM + ktHeight), String.valueOf(seSum));

                        // 合计
                        showText(contentStream, pageWidth - (25 + 27 + 4.5f) * POINTS_PER_MM - (stFont.getStringWidth(invoice.getJeSum()) / 1000 * fontSize9),
                                17 * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM - stHeight / 2), invoice.getJeSum());

                        showText(contentStream, pageWidth - 4.5f * POINTS_PER_MM - (stFont.getStringWidth(invoice.getSeSum()) / 1000 * fontSize9),
                                17 * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM - stHeight / 2), invoice.getSeSum());

                        contentStream.setFont(courierFont, fontSize11);
                        // 小计 人民币符号
                        showText(contentStream, pageWidth - (25 + 27 + 4.5f) * POINTS_PER_MM - (stFont.getStringWidth(String.valueOf(jeSum)) / 1000 * fontSize9 + dkHeight / 2),
                                16 * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM + ktHeight), "y");

                        showText(contentStream, pageWidth - 4.5f * POINTS_PER_MM - (stFont.getStringWidth(String.valueOf(seSum)) / 1000 * fontSize9 + dkHeight / 2),
                                16 * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM + ktHeight), "y");

                        // 合计
                        showText(contentStream, pageWidth - (25 + 27 + 4.5f) * POINTS_PER_MM - (stFont.getStringWidth(invoice.getJeSum()) / 1000 * fontSize9 + dkHeight / 2),
                                17 * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM - stHeight / 2), "y");

                        showText(contentStream, pageWidth - 4.5f * POINTS_PER_MM - (stFont.getStringWidth(invoice.getSeSum()) / 1000 * fontSize9 + dkHeight / 2),
                                17 * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM - stHeight / 2), "y");


                        contentStream.setFont(stFont, fontSize9);
                    }

                    if (ii == indexList.size() - 1) {
                        contentStream.setFont(stFont, fontSize9);
                        // 最后一页
                        if (indexList.size() > 1) {
                            // 小计
                            showText(contentStream, pageWidth - (25 + 27 + 4.5f) * POINTS_PER_MM - (stFont.getStringWidth(String.valueOf(jeSum)) / 1000 * fontSize9),
                                    48.5f * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM - ktHeight / 2), String.valueOf(jeSum));

                            showText(contentStream, pageWidth - 4.5f * POINTS_PER_MM - (stFont.getStringWidth(String.valueOf(seSum)) / 1000 * fontSize9),
                                    48.5f * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM - ktHeight / 2), String.valueOf(seSum));

                        }

                        // 合计
                        showText(contentStream, pageWidth - (25 + 27 + 4.5f) * POINTS_PER_MM - (stFont.getStringWidth(invoice.getJeSum()) / 1000 * fontSize9),
                                45 * POINTS_PER_MM + (4.5f * POINTS_PER_MM / 2 - stHeight / 2), invoice.getJeSum());

                        showText(contentStream, pageWidth - 4.5f * POINTS_PER_MM - (stFont.getStringWidth(invoice.getSeSum()) / 1000 * fontSize9),
                                45 * POINTS_PER_MM + (4.5f * POINTS_PER_MM) / 2 - stHeight / 2, invoice.getSeSum());

                        contentStream.drawImage(dx, 52.734f * POINTS_PER_MM, 37.5f * POINTS_PER_MM, 4 * POINTS_PER_MM, 4 * POINTS_PER_MM);

                        // 价税合计大写
                        showText(contentStream, 56.734f * POINTS_PER_MM, 36 * POINTS_PER_MM + stHeight / 2, invoice.getJsSumStr());

                        // 价税合计小写
                        contentStream.setFont(courierFont, fontSize11);
                        showText(contentStream, pageWidth - 53.5f * POINTS_PER_MM, 36 * POINTS_PER_MM + stHeight / 2, "y");

                        showText(contentStream, pageWidth - 4.5f * POINTS_PER_MM - (stFont.getStringWidth(invoice.getSeSum()) / 1000 * fontSize9 + dkHeight / 2),
                                45 * POINTS_PER_MM + (4.5f * POINTS_PER_MM) / 2 - stHeight / 2, "y");

                        showText(contentStream, pageWidth - (25 + 27 + 4.5f) * POINTS_PER_MM - (stFont.getStringWidth(invoice.getJeSum()) / 1000 * fontSize9 + dkHeight / 2),
                                45 * POINTS_PER_MM + (4.5f * POINTS_PER_MM / 2 - stHeight / 2), "y");

                        if (indexList.size() > 1) {

                            showText(contentStream, pageWidth - 4.5f * POINTS_PER_MM - (stFont.getStringWidth(String.valueOf(seSum)) / 1000 * fontSize9 + dkHeight / 2),
                                    48.5f * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM - ktHeight / 2), "y");

                            showText(contentStream, pageWidth - (25 + 27 + 4.5f) * POINTS_PER_MM - (stFont.getStringWidth(String.valueOf(jeSum)) / 1000 * fontSize9 + dkHeight / 2),
                                    48.5f * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM - ktHeight / 2), "y");
                        }

                        contentStream.setFont(stFont, fontSize9);
                        showText(contentStream, pageWidth - 53.5f * POINTS_PER_MM + dkHeight / 2, 36 * POINTS_PER_MM + stHeight / 2, invoice.getJsSum());

                        List<String> bzList = wrapTextToLines(invoice.getBz(), 195 * POINTS_PER_MM, stFont, fontSize9);

                        for (int i = 0; i < bzList.size(); i++) {
                            showText(contentStream, 11.5f * POINTS_PER_MM, 36f * POINTS_PER_MM - stHeight * (i + 1), bzList.get(i));
                        }

                    }


                    showText(contentStream, ktFont.getStringWidth("开票人:") / 1000 * fontSize9 + 15 * POINTS_PER_MM, 7.5f * POINTS_PER_MM, invoice.getKpr());

                    contentStream.beginText();
                    String text3 = "下载次数:";
                    Matrix rotateMatrix = Matrix.getRotateInstance(-Math.PI / 2, 206.5f * POINTS_PER_MM, pageHeight - 30 * POINTS_PER_MM);
                    contentStream.setTextMatrix(rotateMatrix);
                    for (int i = 0; i < text3.length(); i++) {
                        contentStream.newLineAtOffset(10, 0); // 每次向下移动文字大小的尺寸
                        contentStream.showText(String.valueOf(text3.charAt(i)));
                    }
                    contentStream.endText();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            // 保存PDF文档
            document.save("PdfInvoice.pdf");
            document.close();
            System.out.println("PDF文件已生成！");

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    private static void showText(PDPageContentStream contentStream, float x, float y, String text) throws IOException {
        contentStream.beginText();
        contentStream.newLineAtOffset(x, y); // 移动到下一行
        contentStream.showText(text);
        contentStream.endText();
    }

    private static void drawLine(PDPageContentStream contentStream, PDPage page, int size, int index) throws IOException {

        float pageWidth = page.getMediaBox().getWidth();
        float pageHeight = page.getMediaBox().getHeight();

        // 设置标签框
        contentStream.setLineDashPattern(new float[]{6, 3}, 0);
        contentStream.setLineWidth(1);
        contentStream.moveTo(29f * POINTS_PER_MM, page.getMediaBox().getHeight() - 6 * POINTS_PER_MM);
        contentStream.lineTo(29f * POINTS_PER_MM, page.getMediaBox().getHeight() - 26 * POINTS_PER_MM);
        contentStream.lineTo(57 * POINTS_PER_MM, page.getMediaBox().getHeight() - 26 * POINTS_PER_MM);
        contentStream.lineTo(57 * POINTS_PER_MM, page.getMediaBox().getHeight() - 6 * POINTS_PER_MM);
        contentStream.closeAndStroke();

        // 设置线条宽度
        contentStream.setLineDashPattern(new float[]{0, 0}, 0);

        contentStream.setLineWidth(0.25f * POINTS_PER_MM);
        // 绘制表格线
        contentStream.moveTo(4.5f * POINTS_PER_MM, pageHeight - 30f * POINTS_PER_MM);
        contentStream.lineTo(4.5f * POINTS_PER_MM, 16f * POINTS_PER_MM);
        contentStream.lineTo(205.5f * POINTS_PER_MM, 16f * POINTS_PER_MM);
        contentStream.lineTo(205.5f * POINTS_PER_MM, pageHeight - 30f * POINTS_PER_MM);
        contentStream.closeAndStroke();

        // 购买方信息下侧横线
        contentStream.moveTo(4.5f * POINTS_PER_MM, pageHeight - 52 * POINTS_PER_MM);
        contentStream.lineTo(205.5f * POINTS_PER_MM, pageHeight - 52 * POINTS_PER_MM);

        // 购买方信息竖线
        contentStream.moveTo(10.5f * POINTS_PER_MM, pageHeight - 30 * POINTS_PER_MM);
        contentStream.lineTo(10.5f * POINTS_PER_MM, pageHeight - 52 * POINTS_PER_MM);

        // 销售方信息竖线
        contentStream.moveTo(105f * POINTS_PER_MM, pageHeight - 30 * POINTS_PER_MM);
        contentStream.lineTo(105f * POINTS_PER_MM, pageHeight - 52 * POINTS_PER_MM);

        contentStream.moveTo(111f * POINTS_PER_MM, pageHeight - 30 * POINTS_PER_MM);
        contentStream.lineTo(111f * POINTS_PER_MM, pageHeight - 52 * POINTS_PER_MM);
        // 双横线
        contentStream.moveTo((pageWidth - 73 * POINTS_PER_MM) / 2, pageHeight - 18 * POINTS_PER_MM);
        contentStream.lineTo((pageWidth - 73 * POINTS_PER_MM) / 2 + 73 * POINTS_PER_MM, pageHeight - 18 * POINTS_PER_MM);

        contentStream.moveTo((pageWidth - 73 * POINTS_PER_MM) / 2, pageHeight - 19 * POINTS_PER_MM);
        contentStream.lineTo((pageWidth - 73 * POINTS_PER_MM) / 2 + 73 * POINTS_PER_MM, pageHeight - 19 * POINTS_PER_MM);

        contentStream.closeAndStroke();

        if (index == size - 1) {
            // 最后一页
            // 合计下侧横线
            contentStream.moveTo(4.5f * POINTS_PER_MM, 44 * POINTS_PER_MM);
            contentStream.lineTo(205.5f * POINTS_PER_MM, 44 * POINTS_PER_MM);

            // 备注上侧横线
            contentStream.moveTo(4.5f * POINTS_PER_MM, 36 * POINTS_PER_MM);
            contentStream.lineTo(205.5f * POINTS_PER_MM, 36 * POINTS_PER_MM);

            // 备注右侧竖线
            contentStream.moveTo(10.5f * POINTS_PER_MM, 36 * POINTS_PER_MM);
            contentStream.lineTo(10.5f * POINTS_PER_MM, 16 * POINTS_PER_MM);

            // 价税合计（大写）右侧竖线
            contentStream.moveTo(51.734f * POINTS_PER_MM, 44 * POINTS_PER_MM);
            contentStream.lineTo(51.734f * POINTS_PER_MM, 36 * POINTS_PER_MM);
        }
        contentStream.closeAndStroke();


        // 金色竖线
        float[] goldRGB = new float[]{1.0f, 0.843f, 0.0f}; // 金色的近似RGB值
        PDColor maroonColor2 = new PDColor(goldRGB, PDDeviceRGB.INSTANCE);
        // 设置线条宽度
        contentStream.setLineWidth(0.54f * POINTS_PER_MM);
        // 设置线条颜色为金色
        contentStream.setStrokingColor(maroonColor2);
        contentStream.moveTo(205.5f * POINTS_PER_MM, (pageHeight - 46 * POINTS_PER_MM) / 2 + 16 * POINTS_PER_MM);
        contentStream.lineTo(205.5f * POINTS_PER_MM, 16 * POINTS_PER_MM);
        contentStream.closeAndStroke();


        // 咖色竖线
        float[] coffeeRGB = new float[]{30.2f / 100, 22.35f / 100, 0.0f}; // 咖色的近似RGB值
        PDColor maroonColor3 = new PDColor(coffeeRGB, PDDeviceRGB.INSTANCE);
        // 设置线条宽度
        contentStream.setLineWidth(0.54f * POINTS_PER_MM);
        // 设置线条颜色为咖色
        contentStream.setStrokingColor(maroonColor3);
        contentStream.moveTo(205.5f * POINTS_PER_MM, (pageHeight - 46 * POINTS_PER_MM) / 2 + 16 * POINTS_PER_MM);
        contentStream.lineTo(205.5f * POINTS_PER_MM, 16 * POINTS_PER_MM);
        contentStream.closeAndStroke();

    }

    private static void drawTable(PDPageContentStream contentStream, PDType0Font ktFont, PDPage page, int size, int index) throws IOException {

        float fontSize9 = 9;
        float fontSize20 = 20;
        // 页面宽度和高度
        float pageWidth = page.getMediaBox().getWidth();
        float pageHeight = page.getMediaBox().getHeight();

        float fontH1 = (ktFont.getFontDescriptor().getAscent() - ktFont.getFontDescriptor().getDescent()) / 1000 * fontSize20;


        contentStream.setFont(ktFont, fontSize20);

        String biaoTou = "电子发票（增值税专用发票）";

        float y = (pageHeight - 8 * POINTS_PER_MM - fontH1);
        showText(contentStream, (pageWidth - (ktFont.getStringWidth(biaoTou)) / 1000 * fontSize20) / 2, y, biaoTou);


        contentStream.setFont(ktFont, fontSize9);
        // 获取文字高度
        float fontH = (ktFont.getFontDescriptor().getAscent() - ktFont.getFontDescriptor().getDescent()) / 1000 * fontSize9;

        showText(contentStream, pageWidth - 55 * POINTS_PER_MM, pageHeight - 8 * POINTS_PER_MM - fontH, "发票号码：");

        showText(contentStream, pageWidth - 55 * POINTS_PER_MM, pageHeight - 8 * POINTS_PER_MM - fontH * 2 - 3 * POINTS_PER_MM, "开票日期：");

        contentStream.beginText();
        String gmfxx = "购买方信息";
        float gmfxxHeight = ktFont.getStringWidth(gmfxx) / 1000 * fontSize9;

        contentStream.newLineAtOffset(4.5f * POINTS_PER_MM + (6 * POINTS_PER_MM - fontH) / 2,
                pageHeight - 30f * POINTS_PER_MM - (22f * POINTS_PER_MM - gmfxxHeight) / 2);
        for (int i = 0; i < gmfxx.length(); i++) {
            contentStream.newLineAtOffset(0, -fontH); // 每次向下移动文字大小的尺寸
            contentStream.showText(String.valueOf(gmfxx.charAt(i)));
        }
        contentStream.endText();

        String mc = "名称:";
        String sh = "统一社会信用代码/纳税人识别号:";

        showText(contentStream, 10.5f * POINTS_PER_MM, pageHeight - 36.5f * POINTS_PER_MM - (22f * POINTS_PER_MM - gmfxxHeight) / 2, mc);

        showText(contentStream, 10.5f * POINTS_PER_MM, pageHeight - 45.5f * POINTS_PER_MM, sh);

        contentStream.beginText();
        String xsfxx = "销售方信息";
        contentStream.newLineAtOffset(105f * POINTS_PER_MM + (6 * POINTS_PER_MM - fontH) / 2,
                pageHeight - 30f * POINTS_PER_MM - (22f * POINTS_PER_MM - gmfxxHeight) / 2);
        for (int i = 0; i < xsfxx.length(); i++) {
            contentStream.newLineAtOffset(0, -fontH); // 每次向下移动文字大小的尺寸
            contentStream.showText(String.valueOf(xsfxx.charAt(i)));
        }
        contentStream.endText();

        // 销售方名称与税号
        showText(contentStream, pageWidth - 99 * POINTS_PER_MM, pageHeight - 36.5f * POINTS_PER_MM - (22f * POINTS_PER_MM - gmfxxHeight) / 2, mc);
        showText(contentStream, pageWidth - 99 * POINTS_PER_MM, pageHeight - 45.5f * POINTS_PER_MM, sh);


        JsonNode dataList = getJson();
        float totalWidth = 0;

        // 项目明细表头
        for (int i = 0; i < dataList.size(); i++) {

            JsonNode data = dataList.get(i);
            String name = data.get("name").asText();
            float width = Float.parseFloat(data.get("width").toString());
            String namePosition = data.get("namePosition").asText();

            float nameW = ktFont.getStringWidth(name) / 1000 * fontSize9;

            contentStream.setFont(ktFont, fontSize9);
            float x = 0;
            float yy = pageHeight - 52.5f * POINTS_PER_MM - fontH;

            if ("center".equals(namePosition)) {
                float v = (width * POINTS_PER_MM - nameW) / 2;
                x = (4.5f + totalWidth) * POINTS_PER_MM + v;
            } else if ("right".equals(namePosition)) {
                float v = width * POINTS_PER_MM - nameW;
                x = (4.5f + totalWidth) * POINTS_PER_MM + v;
            } else {
                x = (4.5f + totalWidth) * POINTS_PER_MM;
            }
            showText(contentStream, x, yy, name);
            totalWidth += width;
        }


        if (index == size - 1) {
            // 最后一页
            if (size > 1) {
                showText(contentStream, 15 * POINTS_PER_MM, 48.5f * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM - fontH / 2), "小     计");
            }

            showText(contentStream, 15 * POINTS_PER_MM, 45 * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM - fontH / 2), "合     计");

            showText(contentStream, 15 * POINTS_PER_MM, 36 * POINTS_PER_MM + (8 * POINTS_PER_MM - fontH) / 2, "价税合计（大写）");

            showText(contentStream, pageWidth - 53.5f * POINTS_PER_MM - (ktFont.getStringWidth("（小写）") / 1000 * fontSize9), 36 * POINTS_PER_MM + (8 * POINTS_PER_MM - fontH) / 2, "（小写）");

            // 备注
            contentStream.beginText();

            contentStream.newLineAtOffset(6f * POINTS_PER_MM, 36 * POINTS_PER_MM);
            String text = "备注";
            for (int i = 0; i < text.length(); i++) {
                contentStream.newLineAtOffset(0, -20); // 每次向下移动文字大小的尺寸
                contentStream.showText(String.valueOf(text.charAt(i)));
            }
            contentStream.endText();
        } else {
            showText(contentStream, 15 * POINTS_PER_MM, 17 * POINTS_PER_MM + (4.5f * POINTS_PER_MM - fontH) / 2, "合     计");
            if (size > 1) {
                showText(contentStream, 15 * POINTS_PER_MM, 16 * POINTS_PER_MM + (4.5f / 2 * POINTS_PER_MM + fontH), "小     计");
            }
        }
        showText(contentStream, 15 * POINTS_PER_MM, 7.5f * POINTS_PER_MM, "开票人:");
    }

}
